"""
1.创建类定义
2.创建对象
3.绑定上位函数 绑定下位函数
"""
import inspect
import subprocess
import os,json,sys
import time,platform
import threading    
from urllib.parse import unquote
from urllib.parse import quote
import socket
import gevent
import gevent.server
import tornado.ioloop
import json as JSON

import tornado.web

class base_class:
    #----------------------基础组件执行的相关代码--------------------
    no='_v_None_'#表示空属性
    tree_dct={}
    base_print=print
    #获取传参
    
    #获取传参
    def get_kwargs(self,kwargs):
        for key in kwargs:
            if key in self.in_kwargs:
                self.in_kwargs1[key]=kwargs[key]
    #获取传参
    def get_kwargs2(self,kwargs):
        for key in kwargs:
            if key in self.in_kwargs:
                self.in_kwargs2[key]=kwargs[key]
    #接收self.tree_type=1类型的树传递过来的输入数据
    def input_kwargs(self,**kwargs):
        #获取到参数
        self.get_kwargs(kwargs)
        #检查需要传入参数的函数是否全部传入参数成功
        print("检查传参是否全入:",all(value is not self.no for value in self.in_kwargs1.values()),self.in_kwargs1)
        if all(value is not self.no for value in self.in_kwargs1.values()):
            print(type(self).__name__,"触发传参self.in_kwargs1:",self.in_kwargs1)
            print(type(self).__name__,"被动传参self.in_kwargs2:",self.in_kwargs2)
            print(self.in_kwargs2_ids)
            #如果全部传入成功 则运行被动执行的函数获取传参
            for key,val in self.in_kwargs2_ids.items():
                print("key",key)
                self.get_kwargs2(self._all_obj[key].get_out_kwargs(self._temp_id,val))
            print(type(self).__name__,"被动传参self.in_kwargs2:",self.in_kwargs2)
            print(type(self).__name__,"固定参数和配置设参self.in_kwargs3",self.in_kwargs3)
            self.run_mid()
    def server_input_kwargs(self,**kwargs):
        #获取到参数
        self.get_kwargs(kwargs)
        #检查需要传入参数的函数是否全部传入参数成功
        if all(value is not self.no for value in self.in_kwargs1.values()):
            print(type(self).__name__,"触发传参self.in_kwargs1:",self.in_kwargs1)
            #如果全部传入成功 则运行被动执行的函数获取传参
            for out_id,val in self.in_kwargs2_ids.items():
                self.get_kwargs2(self._all_obj[out_id].get_out_kwargs(self._temp_id,val))
            print(type(self).__name__,"被动传参self.in_kwargs2:",self.in_kwargs2)
            print(type(self).__name__,"固定参数和配置设参self.in_kwargs3",self.in_kwargs3)
            new_kwargs={}
            new_kwargs.update(self.in_kwargs1)
            new_kwargs.update(self.in_kwargs2)
            new_kwargs.update(self.in_kwargs3)
            self.run2(**new_kwargs)

    #接收self.tree_type=1类型的树传递过来的输入数据
    def input_kwargs2(self,**kwargs):
        #获取到参数
        self.get_kwargs(kwargs)
        #检查需要传入参数的函数是否全部传入参数成功
        if all(value != self.no for value in self.in_kwargs1.values()):
            print("self.in_kwargs1",self.in_kwargs1)
            #如果全部传入成功 则运行被动执行的函数获取传参
            print(type(self).__name__,"开始获取参数",self.in_kwargs2)
            for key,val in self.in_kwargs2_ids.items():
                self.get_kwargs2(self._all_obj[key].get_out_kwargs(self._temp_id,val))
            print(type(self).__name__,"接收到所有参数,触发参数:",self.in_kwargs1,"固定参数:",self.in_kwargs2)
    #将run运行后的参数 转为指定树需要的传参
    def to_kwargs(self,kwargs,value):
        res={}
        # print(kwargs,value)
        for k,v in value.items():
            res[v]=kwargs[k]
        # print("end")
        return res
    def get_kwargs(self,kwargs):
        for k,val in kwargs.items():
            self.in_kwargs1[k]=val
    def get_kwargs2(self,kwargs):
        for k,val in kwargs.items():
            self.in_kwargs2[k]=val
    def in_kwargs_init(self):
        self.in_kwargs1={k:self.no for k in self.in_kwargs1}
    def get_out_kwargs(self,tree_id,params):
        t=time.time()
        new_kwargs={}
        new_kwargs.update(self.in_kwargs2)
        new_kwargs.update(self.in_kwargs3)
        print("new_kwargs1",new_kwargs)
        out_params=self.run(**new_kwargs)#运行函数
        self.in_kwargs2={item:self.no for item in self.in_kwargs2}
        # print(out_params)
        return self.to_kwargs(out_params,params)
    
    def get_out_kwargs2(self,tree_id,params):
        t=time.time()
        new_kwargs={}
        new_kwargs.update(self.in_kwargs2)
        new_kwargs.update(self.in_kwargs3)
        print("new_kwargs2",new_kwargs)
        out_params=self.run(**new_kwargs)#运行函数
        self.in_kwargs2={item:self.no for item in self.in_kwargs2}
        # print(out_params)
        return self.to_kwargs(out_params,params)
        # self._all_obj[tree_id].input_kwargs2(**self.to_kwargs(out_params,self.out_kwargs_info[tree_id]))
        # print(self._name,"结束运行",'%.2f'%(time.time()-t))
    def run(self,**kwargs):
        print(type(self).__name__,'运行ccc')
        res={}
        return res
    def print(self,*a,print_flag=False,**b):
        self.print_str+=(' '.join([str(i)for i in a])+'\n')
        if print_flag is True:print(*a,**b)
    def send_print(self):
        print(type(self).__name__,'运行日志:',self.print_str)
        self.print_str=''
    #-----------------------------会创建进程的类  相关的代码--------------------------
    base_import_lst=[
        "import inspect",
        "import subprocess",
        "import os,json,sys",
        "import time,platform",
        "import threading" ,
        "from urllib.parse import unquote",
        "from urllib.parse import quote",
        "import socket",
        "import gevent",
        "import gevent.server",
        ]
    
    @classmethod
    def write_pid(self,pid):
        self.pid_dir=r'E:\my\pid_dir'
        with open(self.pid_dir+os.sep+self.__class__.__name__ ,'w',encoding='utf-8')as f:
            f.write(str(pid))
    _process_dct={}#如果组件另开进程，需要在另开的进程内创建
    _all_obj={}
        #编码
    @classmethod
    def _encode_url(cls,data):
        """
        将含有特殊字符的字符串进行 URL 编码。
        
        :param data: 字符串
        :return: 编码后的字符串
        """
        encoded_data = quote(data, safe='')
        return encoded_data
    #解码
    @classmethod
    def _decode_url(cls,encoded_data):
        """
        将 URL 编码后的字符串解码。
        
        :param encoded_data: 编码后的字符串
        :return: 解码后的字符串
        """
        decoded_data = unquote(encoded_data)
        return decoded_data
    
    @classmethod
    def _encode2(cls,data):
        return cls._encode_url(json.dumps(data))
    @classmethod
    def _decode2(cls,data):
        return json.loads(cls._decode_url(data)) 
    def __init__(self,*args,**kwargs):
        sys.stdout.reconfigure(encoding='utf-8')
        sys.stderr.reconfigure(encoding='utf-8')

        
# public_data={'all_obj':{}}
# public_data['all_process_info']={'1': {'recv_ip': '127.0.0.1', 'recv_port': 5555}}
# public_data['flow_dict']={'1': {'version': 0, 'name': 'mqtt初始化', 'index': 0, 'version_name': '第一个版本', 'edit_use': '*', 'note': '会创建进程,进程内连接mqtt服务器,然后监听topic进行处理。', 'temp_type': 'process', 'tree_type': 0, 'process_name': 'mqtt进程', 'in_kwargs': {'0': {'name': 'mqtt_address', 'note': 'mqtt地址', 'default': '127.0.0.1', 'type': 'str', 'in_type1': '0', 'v0': '127.0.0.1', 'v1_': [None, None], 'v2': '', 'in_type3': '0'}, '1': {'name': 'mqtt_port', 'note': 'mqtt端口', 'default': 1883, 'type': 'int', 'in_type1': '0', 'v0': 1883, 'v1_': [None, None], 'v2': '', 'in_type3': '0'}, '2': {'name': 'mqtt_username', 'note': 'mqtt登录用户名', 'default': 'default', 'type': 'str', 'in_type1': '0', 'v0': 'default', 'v1_': [None, None], 'v2': '', 'in_type3': '0'}, '3': {'name': 'mqtt_passwd', 'note': 'mqtt登录密码', 'default': 'default', 'type': 'str', 'in_type1': '0', 'v0': 'default', 'v1_': [None, None], 'v2': '', 'in_type3': '0'}, '4': {'name': 'mqtt_client_name', 'note': 'mqtt注册名称', 'default': 'client_name', 'type': 'str', 'in_type1': '0', 'v0': 'client_name', 'v1_': [None, None], 'v2': '', 'in_type3': '0'}, '5': {'name': 'recv_port', 'note': '进程接收其他进程消息的socket服务端口', 'default': 5555, 'type': 'int', 'in_type1': '0', 'v0': 5555, 'v1_': [None, None], 'v2': '', 'in_type3': '0'}, '6': {'name': 'recv_ip', 'note': '进程接收其他进程消息的socket服务ip', 'default': '127.0.0.1', 'type': 'str', 'in_type1': '0', 'v0': '127.0.0.1', 'v1_': [None, None], 'v2': '', 'in_type3': '0'}, '-1': {'name': 'flag', 'note': '通过传入值来控制组件的运行顺序 不传值时表示按照默认方式运行', 'default': '0', 'type': 'str', 'in_type1': '0', 'v0': '0', 'v1_': [None, None], 'v2': '', 'in_type3': '0'}}, 'out_kwargs': {'0': {'name': '进程通信端口', 'note': 'mqtt进程的recv_port', 'type': 'int'}, '1': {'name': 'mqtt对象', 'note': 'mqtt进程的recv_port', 'type': 'int', 'out_params': {'5': {'0': {'key': ['2', '1']}}, '6': {'0': {'key': ['3', '1']}}}}, '-1': {'name': 'flag', 'note': '将传入的flag值输出', 'default': '0', 'type': 'str'}}, 'temp_id': 'a_1_0_0_0', 'tree_type_from': {}, 'tree_from': None, 'process_id': '1', 'process_from': {'1': ['1']}, 'process_change': True, 'temp_name': 'mqtt初始化', 'x': 162, 'y': 85, 'out_idx': '3', 'in_idx': 0, 'out': {'2': {'out_id': '5', 'out_key': '1'}, '3': {'out_id': '6', 'out_key': '1'}}, 'in': {}}, '5': {'version': 0, 'name': '收mqtt数据', 'index': 0, 'version_name': '第一个版本', 'edit_use': '*', 'note': '监听topic然后将获取到的topic_lst和data输出,仅支持绝对topic和/#语法', 'id': '基础组件_mqtt通信_收mqtt数据', 'tree_type': '1', 'other_process_note': '在其他进程运行会有额外的进程间通信开销', 'in_kwargs': {'0': {'name': 'mqtt对象', 'note': 'mqtt初始化后传出的对象', 'default': '', 'type': 'int', 'in_type1': '1', 'v0': '', 'v1_': ['1', '1'], 'v2': '', 'in_type3': '0', 'in_params': ['1', '1', ['2', '1']]}, '1': {'name': '收topic', 'note': '只支持绝对匹配以及/#匹配,匹配速度100w条小于0秒', 'default': 'test/#', 'type': 'str', 'in_type1': '0', 'v0': 'test/#', 'v1_': [None, None], 'v2': '', 'in_type3': '0'}, '-1': {'name': 'flag', 'note': '通过传入值来控制组件的运行顺序 不传值时表示按照默认方式运行', 'default': '0', 'type': 'str', 'in_type1': '0', 'v0': '0', 'v1_': [None, None], 'v2': '', 'in_type3': '0'}}, 'out_kwargs': {'0': {'name': 'topic_lst', 'note': 'topic列表以/分割', 'type': 'list'}, '1': {'name': 'data', 'note': 'topic原始数据', 'type': 'str', 'out_params': {'4': {'0': {'key': ['1', '1']}}}}, '-1': {'name': 'flag', 'note': '将传入的flag值输出', 'default': '0', 'type': 'str'}}, 'temp_id': 'a_1_0_0_2', 'tree_type_from': {}, 'tree_from': ['5'], 'process_id': '1', 'process_from': {'1': ['1', '5']}, 'temp_name': '收mqtt数据', 'x': 81, 'y': 194, 'out_idx': '1', 'in_idx': '1', 'out': {'1': {'out_id': '4', 'out_key': '1'}}, 'in': {'1': {'in_id': '1', 'in_key': '2'}}}, '4': {'version': 0, 'name': '发mqtt数据', 'index': 0, 'version_name': '第一个版本', 'edit_use': '*', 'id': '基础组件_mqtt通信_发mqtt数据', 'tree_type': '1', 'in_kwargs': {'0': {'name': 'mqtt对象', 'note': 'mqtt初始化后传出的对象', 'default': '', 'type': 'int', 'in_type1': '1', 'v0': '', 'v1_': ['5', '1'], 'v2': '', 'in_type3': '0', 'in_params': ['5', '1', ['1', '1']]}, '1': {'name': 'topic', 'note': '要发送的topic', 'default': '/wewe', 'type': 'int', 'in_type1': '0', 'v0': '/wewe', 'v1_': [None, None], 'v2': '', 'in_type3': '0'}, '2': {'name': 'info', 'note': '要发送的数据', 'default': '', 'type': 'dict', 'in_type1': '0', 'v0': '', 'v1_': [None, None], 'v2': '', 'in_type3': '0'}, '-1': {'name': 'flag', 'note': '通过传入值来控制组件的运行顺序 不传值时表示按照默认方式运行', 'default': '0', 'type': 'str', 'in_type1': '0', 'v0': '0', 'v1_': [None, None], 'v2': '', 'in_type3': '0'}}, 'out_kwargs': {'0': {'name': '输出数据', 'note': '输出数据'}, '-1': {'name': 'flag', 'note': '将传入的flag值输出', 'default': '0', 'type': 'str'}}, 'temp_id': 'a_1_0_0_1', 'tree_type_from': {}, 'tree_from': ['5', '4'], 'process_id': '1', 'process_from': {'1': ['1', '5', '4']}, 'temp_name': '发mqtt数据', 'x': 65, 'y': 312, 'out_idx': 0, 'in_idx': '1', 'out': {}, 'in': {'1': {'in_id': '5', 'in_key': '1'}}}, '6': {'version': 0, 'name': '收mqtt数据', 'index': 0, 'version_name': '第一个版本', 'edit_use': '*', 'note': '监听topic然后将获取到的topic_lst和data输出,仅支持绝对topic和/#语法', 'id': '基础组件_mqtt通信_收mqtt数据', 'tree_type': '1', 'other_process_note': '在其他进程运行会有额外的进程间通信开销', 'in_kwargs': {'0': {'name': 'mqtt对象', 'note': 'mqtt初始化后传出的对象', 'default': '', 'type': 'int', 'in_type1': '1', 'v0': '', 'v1_': ['1', '1'], 'v2': '', 'in_type3': '0', 'in_params': ['1', '1', ['3', '1']]}, '1': {'name': '收topic', 'note': '只支持绝对匹配以及/#匹配,匹配速度100w条小于0秒', 'default': 'test/#', 'type': 'str', 'in_type1': '0', 'v0': 'test/#', 'v1_': [None, None], 'v2': '', 'in_type3': '0'}, '-1': {'name': 'flag', 'note': '通过传入值来控制组件的运行顺序 不传值时表示按照默认方式运行', 'default': '0', 'type': 'str', 'in_type1': '0', 'v0': '0', 'v1_': [None, None], 'v2': '', 'in_type3': '0'}}, 'out_kwargs': {'0': {'name': 'topic_lst', 'note': 'topic列表以/分割', 'type': 'list', 'out_params': {'7': {'0': {'key': ['1', '1']}}}}, '1': {'name': 'data', 'note': 'topic原始数据', 'type': 'str'}, '-1': {'name': 'flag', 'note': '将传入的flag值输出', 'default': '0', 'type': 'str'}}, 'temp_id': 'a_1_0_0_2', 'tree_type_from': {}, 'tree_from': ['6'], 'process_id': '1', 'process_from': {'1': ['1', '6']}, 'temp_name': '收mqtt数据', 'x': 237, 'y': 189, 'out_idx': '1', 'in_idx': '1', 'out': {'1': {'out_id': '7', 'out_key': '1'}}, 'in': {'1': {'in_id': '1', 'in_key': '3'}}}, '7': {'version': 0, 'name': '发mqtt数据', 'index': 0, 'version_name': '第一个版本', 'edit_use': '*', 'id': '基础组件_mqtt通信_发mqtt数据', 'tree_type': '1', 'in_kwargs': {'0': {'name': 'mqtt对象', 'note': 'mqtt初始化后传出的对象', 'default': '', 'type': 'int', 'in_type1': '1', 'v0': '', 'v1_': ['6', '0'], 'v2': '', 'in_type3': '0', 'in_params': ['6', '0', ['1', '1']]}, '1': {'name': 'topic', 'note': '要发送的topic', 'default': '/wewe', 'type': 'int', 'in_type1': '0', 'v0': '/wewe', 'v1_': [None, None], 'v2': '', 'in_type3': '0'}, '2': {'name': 'info', 'note': '要发送的数据', 'default': '', 'type': 'dict', 'in_type1': '0', 'v0': '', 'v1_': [None, None], 'v2': '', 'in_type3': '0'}, '-1': {'name': 'flag', 'note': '通过传入值来控制组件的运行顺序 不传值时表示按照默认方式运行', 'default': '0', 'type': 'str', 'in_type1': '0', 'v0': '0', 'v1_': [None, None], 'v2': '', 'in_type3': '0'}}, 'out_kwargs': {'0': {'name': '输出数据', 'note': '输出数据'}, '-1': {'name': 'flag', 'note': '将传入的flag值输出', 'default': '0', 'type': 'str'}}, 'temp_id': 'a_1_0_0_1', 'tree_type_from': {}, 'tree_from': ['6', '7'], 'process_id': '1', 'process_from': {'1': ['1', '6', '7']}, 'temp_name': '发mqtt数据', 'x': 234, 'y': 303, 'out_idx': 0, 'in_idx': '1', 'out': {}, 'in': {'1': {'in_id': '6', 'in_key': '1'}}}}
# public_data['run_dir']=r'e:\my\user_dir\1\self\1\projects\1\flow_dir\1\run_flow\now_run_process'
# public_data['project_path']=('1', '1', '1', '1')
# from easy_edit._server.flow_dir.a1.a0.a0.a0.history.a0.main import a_1_0_0_0_0
# #组件id:1 组件名称:mqtt初始化
# flow_obj_1=a_1_0_0_0_0(public_data=public_data,temp_id="1")
        print("kwargs",kwargs)
        self.public_data=kwargs.get("public_data")#公共数据
        self._all_obj=self.public_data.get("all_obj")
        self._flow_dict=self.public_data.get("flow_dict")
        self._all_process_info=self.public_data.get("all_process_info")
        self._run_dir=self.public_data.get("run_dir")#当前项目文件夹下 当前流程文件夹
        self._project_path=self.public_data.get('project_path')#项目路径


        self.kwargs=kwargs
        self._temp_id=str(kwargs.get("temp_id","None"))#流程中被拖拽的组件id
        self._flow_data=self._flow_dict[self._temp_id]
        self._process_id=self._flow_data['process_id']
        self._name=self._flow_data.get("name","None")#流程中被拖拽的组件id
        if self._name in [None,"None"]:raise Exception("333")
        print(f"组件属性:")
        print("\t当前进程正在运行的文件夹",self.kwargs.get("run_dir"))
        print("\t项目所属用户:",self._project_path[0])
        print("\t项目所属目录1:",self._project_path[1])
        print("\t项目所属id:",self._project_path[2])
        print("\t所属流程id:",self._project_path[3])
        print("\t\t流程内组件id:",self._temp_id)
        print("\t\t流程内组件名:",self._name)
        print("\t\t组件模板名:",self._flow_data.get("temp_name"))
        print("\t\t流程内所属进程id:",self._process_id)
        self._change_temp=self._flow_data.get("change_temp")
        if self._change_temp is True:
            print("\t\t流程内组件版本号:自定义")
        else:
            print("\t\t流程内组件:",self._flow_data.get("temp_id")+'_'+str(self._flow_data.get("version")))
            print("\t\t流程内组件版本号id:",self._flow_data.get("version"))
        # self._init_kwargs1()
        print(self._flow_data)
        if self._flow_data.get('temp_type')=="process":
            print("##########",)
            self.process_input=self.process_input_init()
            # self._recv_thread()#与其他进程进行通信的socket服务（用于接收数据
        self.init()
        # if self.process_id is not None:
        #     self._process_dct[self.process_id].create_
        # self.init(**kwargs)
        # self.in_params=kwargs.get("in_params")
        # self.out_params=kwargs.get("out_params")
        # self._name=kwargs.get("name")
        self._all_obj[self._temp_id]=self
    def process_input_init(self):
        
        in_d=self._flow_data['in_kwargs']
        res={}
        for kkk in in_d:
            if in_d[kkk]['in_type1']=='0':#固定参数
                res[in_d[kkk]['name']]=in_d[kkk]['v0']
            elif in_d[kkk]['in_type1']=='1':#组件传参
                pass
                # if len(in_put2)==0:
                #     before="{'"
                # else:
                #     before=",'"
                # fff=in_d[kkk]['in_params']
                # in_put2=in_put2+before+in_d[kkk]['name']+f"':res_{fff[0]}['"+self.data[fff[0]]['out_kwargs'][fff[1]]['name']+"']"
            elif  in_d[kkk]['in_type1']=='2':#配置传参
                res[in_d[kkk]['name']]=in_d[kkk]['v2_val']
        print("res:",res)
        return res
    def _init_kwargs1(self):
        self.in_kwargs1={}#触发类函数 传递的参数 存放字典
        self.in_kwargs2={}#被动类函数 传递的参数 存放字典
        self.in_kwargs2_ids={}
        self.in_kwargs3={}#固定参数  如固定传参或者 配置设参
        self.out_kwargs_info={}#输出参数到函数的字典
        in_kwargs=self._flow_data.get("in_kwargs",{})
        out_kwargs=self._flow_data.get("out_kwargs",{})
        #接收参数  从其他组件中
        for key,value in in_kwargs.items():
            #传参名称
            name=value['name']
            #传参方式
            in_type=value['in_type1']
            if in_type =='0':
                self.in_kwargs3[name]=value.get("v0",value.get("default"))#self.in_kwargs3={"收参名称1":'固定参数1',"收参名称2":'固定参数2'...}
            elif in_type=='2':
                self.in_kwargs3[name]=value['v2']
            elif in_type=='1':
                out_id,out_key=value['v1_']
                #==1表示是触发类函数
                tree_type=self._flow_dict[out_id]["tree_type"]
                if tree_type=="1":#self.in_kwargs1={"收参名称1":收参值1(slef.no表示还未传入参数),"收参名称2":收参值2(slef.no表示还未传入参数),...}
                    self.in_kwargs1[name]=self.no
                #==0表示被动类函数
                else:#self.in_kwargs2_ids={"传参组件id1":{"传参输出参数名1":"收参名称1"},"传参组件id2":{"传参输出参数名2":"收参名称2"},...}
                    print("被动参数")
                    self.in_kwargs2[name]=self.no
                    if self.in_kwargs2_ids.get(out_id)is None:
                        self.in_kwargs2_ids[out_id]={}
                    self.in_kwargs2_ids[out_id][self._flow_dict[out_id]["out_kwargs"][out_key]["name"]]=name
        #输出参数 到其他组件中
        for key,value in out_kwargs.items():
            out_params=value.get("out_params")
            if out_params is not None:
                for in_id,value2 in out_params.items():
                    in_kwargsx=self._flow_dict[in_id]['in_kwargs']
                    out_params=[in_kwargsx[kkkk]['name'] for kkkk in value2.keys()]
                    if self.out_kwargs_info.get(in_id) is None:self.out_kwargs_info[in_id]={}
                    self.out_kwargs_info[in_id][value['name']]=out_params
        print("\t触发类函数 传递的参数 存放字典:",self.in_kwargs1)
        print("\t被动类函数 传递的参数 存放字典:",self.in_kwargs2)
        print("\t固定参数  如固定传参或者 配置设参:",self.in_kwargs3)
        print("\t输出参数到函数的字典:",self.out_kwargs_info)
    def init(*a,**k):
        pass
    @classmethod
    def create_class(cls,python_str):
        exec(python_str)
    @classmethod
    def delete_class(cls,class_name):
        exec("del "+class_name)

    #创建当前进程与其他进程通信 的收发通道
    def _recv_thread(self,sleep_time=0):
        time.sleep(sleep_time)
        th2 = threading.Thread(target=self._recv, args=())
        th2.setDaemon(True)
        th2.start()
        th2.join(0)
    #将next后需要执行的数据 传入进程中
    def send_next_data(self,**kwargs):
        pass
    #非相同进程时 send_next替代run_next
    def send_next(self,**kwargs):
        pass

    def run_mid(self,**kwargs):
        print(self._name,"开始运行")
        t=time.time()
        new_kwargs={}
        new_kwargs.update(self.in_kwargs1)
        new_kwargs.update(self.in_kwargs2)
        new_kwargs.update(self.in_kwargs3)
        out_params=self.run(**new_kwargs)#运行函数
        self.in_kwargs1={k:self.no for k in self.in_kwargs1}
        self.in_kwargs2={k:self.no for k in self.in_kwargs2}
        print(self._name,"结束运行",'%.2f'%(time.time()-t))
        if out_params is None:return
        print("self.out_kwargs_info",self.out_kwargs_info)
        print("out_params",out_params)
        # print("all_obj",self._all_obj)
        # value={'进程通信端口': ['mqtt对象','eee']}
        # out_params={'进程通信端口':1}
        # {item:out_params[k]  for k,v in value.items()for item in v}   =    {'mqtt对象': 1, 'eee': 1}
        self.out(out_params)
    def out(self,out_params):
        # out_params={"mqtt对象":(self._temp_id,self._process_id,self.recv_port),"进程通信端口":self.recv_port}
        for key,value in self.out_kwargs_info.items():
            out_params2={item:out_params[k]  for k,v in value.items()for item in v}
            #如果是当前进程则直接调用当前进程对象 执行传参
            if self._all_obj[key]._process_id==self._process_id:
                self._all_obj[key].input_kwargs(**out_params2)
            else:
                #如果被传参组件与当前组件不属于同一个进程 则通过socket发送数据到目标进程
                process_info=self._all_process_info[key]#获取目标组件进程的ip和端口
                process_ip=process_info['recv_ip']
                process_port=process_info['recv_port']
                self.send_message(server_ip=process_ip,port=process_port,v255_flag=0,message_dct={"temp_id":key,"out_params":out_params2})
    #接收其他进程发送过来的 传参和组件id
    def handle_0(self,**kwargs):
        message_dct=kwargs.get("message_dct")
        temp_id=message_dct['temp_id']
        out_params=message_dct['out_params']
        try:
            self._all_obj[temp_id].input_kwargs(**out_params)
        except:
            print("创建计时器传递数据")
            # 创建一个Timer实例，延迟5秒执行my_function  
            timer = threading.Timer(5.0, self.handle_0,kwargs=kwargs)  
            # 启动计时器  
            timer.start()  
    def _getsource(self):
        return inspect.getsource(self.__class__)
    # def _delete_process(self):
    #     # 终止进程
    #     os.kill(self.process_id, 9)  # 9 表示SIGKILL信号，强制结束进程
    def handle(self,gev_obj,socket,address):
        while True:
            data = socket.recv(1024)
            if not data:
                break
            try:
                v255_flag=str(data[0])
                message_dct= data[1:].decode('utf-8')  
                # 将解码后的字符串解析为字典  
                try:message_dct = json.loads(message_dct)  
                except:pass
                self.handle_switch[v255_flag](message_dct=message_dct,gev_obj=gev_obj,socket=socket,address=address)
            except:pass
    def handle_1(self,**kwargs):
        message_dct=kwargs.get("message_dct")
    def _recv(self):
        #开启单线程tcp服务器 端口为self.recv_port 处理函数为self.handle 
        ##发送10w条数据(0-10w) 可以达到10000/s  在windows 32G内存 2G处理器 
        class new_class(gevent.server.StreamServer):
            def handle(gev,socket,address):
                self.handle(gev,socket,address)
                
        self.recv_port=self.process_input.get('recv_port')
        self.recv_ip=self.process_input.get('recv_ip')
        gevent_obj=new_class((self.recv_ip,self.recv_port))
        gevent_obj.serve_forever()
    @classmethod
    def _recv_http_test(self):
        class MainHandler(tornado.web.RequestHandler):
            def prepare(http_obj):
                self.head_params=http_obj.request.arguments
                self.body_json = http_obj.body_params=None
                try:
                    http_obj.body_json = http_obj.body_params=http_obj.request.body
                    while not isinstance(http_obj.body_json,dict):
                        http_obj.body_json =JSON.loads(http_obj.body_json)
                except ValueError:
                    http_obj.body_json = {'error':'不是json格式'}
            async def post(http_obj):
                print("????http_obj.body_json",http_obj.body_json)
                # 从请求中解析 type 和 data 参数
                type_param = http_obj.body_json.get('type_param')
                data_param = http_obj.body_json.get('data_param')
                self.handle_http_test(http_obj,type_param,data_param)
        app = tornado.web.Application([(r"/", MainHandler),])
        app.listen(port=10002,address="127.0.0.1")
        print("run test http: 127.0.0.1:10002")
        tornado.ioloop.IOLoop.current().start()
    def _recv_http(self):
        class MainHandler(tornado.web.RequestHandler):
            def prepare(http_obj):
                self.head_params=http_obj.request.arguments
                self.body_json = http_obj.body_params=None
                try:
                    http_obj.body_json = http_obj.body_params=http_obj.request.body
                    while not isinstance(http_obj.body_json,dict):
                        http_obj.body_json =JSON.loads(http_obj.body_json)
                except ValueError:
                    http_obj.body_json = {'error':'不是json格式'}
            async def post(http_obj):
                # 从请求中解析 type 和 data 参数
                type_param = http_obj.body_json.get('type')
                data_param = http_obj.body_json.get('data')
                self.handle_http(http_obj,type_param,data_param)
        app = tornado.web.Application([(r"/", MainHandler),])
        app.listen(port=self.process_input.get('recv_port'),address=self.process_input.get('recv_ip'))
        tornado.ioloop.IOLoop.current().start()
    @classmethod
    def handle_http_test(self,http_obj,type_param,data_param):
        http_obj.write({"type": type_param, "data": data_param})
    def handle_http(self,http_obj,type_param,data_param):
        http_obj.write({"type": type_param, "data": data_param})
    def send_message(self,server_ip="127.0.0.1",port=5555,v255_flag=10,message_dct=None):
        """
        v255_flag 表示类型 可以设置0-255 self.handle根据这个类型来处理数据
        message_dct 是要发送的字典数据
        """
        try:
            with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
                sock.settimeout(0.5)  # 设置超时时间为500ms
                sock.connect((server_ip, port))
                message=bytes([v255_flag])+json.dumps(message_dct).encode('utf-8')
                sock.sendall(message)
                response = sock.recv(1024)
                return response
        except:
            return False
    def check_server_obj(self,**kwargs):
        if self.send_message(kwargs.get("recv_port"),kwargs.get("recv_ip"),v255_flag=0,message_dct={"A":True}) is False:
            print("开始创建  bat or shell")
            self.create_bat_or_shell(**kwargs)
            print("开始创建  py file")
            self.create_py_file(**kwargs)
            print("开始运行 server")
            self._create_process(**kwargs)
        return kwargs.get("recv_port")
    
    def run2(self,**kwargs):
        print("run kwargs:",kwargs)
        res=self.check_server_obj(**kwargs)
    def 当前流程所在目录(self):
        
        self._project_path=self.kwargs.get('project_path')#项目路径
        self._flow_data=self._flow_dict[self._temp_id]
        self._process_id=self._flow_data['process_id']
        self._name=self._flow_data.get("name","None")#流程中被拖拽的组件id
        if self._name in [None,"None"]:raise Exception("333")
        print(f"组件属性:")
        print("\t项目所属用户:",self._project_path[0])
        print("\t项目所属目录1:",self._project_path[1])
        print("\t项目所属目录2:",self._project_path[2])
        print("\t项目所属id:",self._project_path[3])
        print("\t所属流程id:",self._project_path[4])
    def create_bat_or_shell(self,**k):
        #要运行的文件夹
        run_process_dir=self._run_dir+os.sep
        process_file_name=f"process_{self._process_id}"
        try:os.makedirs(run_process_dir)
        except:pass
        #要运行的py文件和 保存日志的文件
        self.py_file_path=run_process_dir+process_file_name+".py"
        self.log_file_path=run_process_dir+process_file_name+".log"
        #生成windows下的启动脚本
        if self.check_windows()is True:
            self.bat_file_path=run_process_dir+process_file_name+".bat"
            
                # write_str="\n".join(["# -*- coding: utf-8 -*-",f"file_str=r'''{file_str}'''\n",file_str,f"print('{process_id} end!')"])
            with open(self.bat_file_path,'w',encoding='utf-8')as f:
                f.write('\n'.join(['@echo off',
                                    'if "%1" == "h" goto begin',
                                    'mshta vbscript:createobject("wscript.shell").run("""%~0"" h",0)(window.close)&&exit',
                                    ':begin',
                                   'setlocal',
                                   ':: 设置日志文件的路径',
                                   f'set LOG_FILE={self.log_file_path}',
                                   ':: 执行Python脚本,并将输出和错误重定向到同一个日志文件  ',
                                   f'python -u {self.py_file_path} > "%LOG_FILE%" 2>&1 ',
                                   ":: 结束批处理文件",
                                   "endlocal",
                                   ]))
        else:
             
        #生成ubuntu下的启动脚本
            self.bat_file_path=run_process_dir+process_file_name+".sh"
            with open(self.bat_file_path,'w',encoding='utf-8')as f:
                f.write('\n'.join([
"#!/bin/bash",
f"(python3 -u {self.py_file_path} &> {self.log_file_path} &)"
                                   ]))
        print("生成脚本文件:",self.bat_file_path)
            
    def create_py_file(self,**k):
        run_process_dir=self._run_dir+os.sep
        process_file_name=f"process_{self._process_id}"
        try:os.makedirs(run_process_dir)
        except:pass
        self.py_file_path=run_process_dir+process_file_name+".py"
        # print("create_py_file",k)
        #创建py文件
        with open(self.py_file_path,'w',encoding="utf-8") as f:
            file_str="# -*- coding: utf-8 -*-\n"
            file_str+=self.kwargs.get("_file_str")
            file_str=file_str.replace(r"process_data={}##",f"process_data={k}")
            file_str=file_str.replace("_file_str=file_str,","")
            file_str=file_str.replace("server_input_kwargs()","run_server()")
            f.write(file_str)
        print("生成运行的py文件:",self.py_file_path)
    def _create_process(self,**k):
        # self.bat_file_path=r'E:\my\easy_edit\_base_tool\python\run_process\None_None\mqtt_test\server3.bat'
        # self.bat_file_path
        # 构建命令行参数
        if self.check_windows():
            subprocess.Popen(f'start "" {self.bat_file_path}', shell=True)
        else:
            subprocess.Popen(['bash', self.bat_file_path], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) 
            

    def check_windows(self):
        # 判断操作系统
        if os.name == 'nt':
            print("当前环境是 Windows")
            return True
        else:
            return False
        # elif os.name == 'posix':
        #     if os.uname().sysname == 'Linux':
        #         return False
class zz(base_class):
    def init(self,**kwargs):pass
    def run(self,**kwargs):
        pass
if __name__=="__main__":
    a=base_class(**{
        "name":"obj1",
        "in_params":{"p1":"_&","p2":"_&"},
    "out_params":{
        1:{"out_obj":"obj2",
                "out_params":{
                    "p1":"params1"
                }},
    
    }
    })
    b=base_class(**{
        "name":"obj2",
        "in_params":{"params1":"_&","params2":"_&"},
    "out_params":{
    
    }
    })
    
    c=zz(**{
        "name":"obj3",
        "in_params":{"p1":"_&","p2":"_&"},
    "out_params":{
        1:{"out_obj":"obj2",
                "out_params":{
                    "p2":"params2"
                }},
    
    }
    })
    a.run_next(**{"p1":1,"p2":1})
    c.run_next(**{"p1":1,"p2":1})
    {
    "base_info": {
        "idx": 1
    },
    "dict": {
        "1": {
            "flow_chat_base_info": {
                "idx": 6,
                "flow_chat_name": "发"
            },
            "flow_chat_use_compontent": {
                "1": {
                    "temp_name": "mqtt初始化",
                    "name": "mqtt初始化",
                    "x": 69.39999389648438,
                    "y": 65.19999694824219,
                    "out_idx": 1,
                    "in_idx": 0,
                    "out": {
                        "1": {
                            "out_id": "2",
                            "name": "mqtt初始化->收mqtt数据"
                        }
                    },
                    "in": {}
                },
                "2": {
                    "temp_name": "收mqtt数据",
                    "name": "收mqtt数据",
                    "x": 70.39999389648438,
                    "y": 177.1999969482422,
                    "out_idx": 1,
                    "in_idx": 0,
                    "out": {
                        "1": {
                            "out_id": "3",
                            "name": "收mqtt数据->手写函数"
                        }
                    },
                    "in": {}
                },
                "3": {
                    "temp_name": "手写函数",
                    "name": "手写函数",
                    "x": 76.39999389648438,
                    "y": 255.1999969482422,
                    "out_idx": 1,
                    "in_idx": 0,
                    "out": {
                        "1": {
                            "out_id": "4",
                            "name": "手写函数->写数据库"
                        }
                    },
                    "in": {}
                },
                "4": {
                    "temp_name": "写数据库",
                    "name": "写数据库",
                    "x": 69.39999389648438,
                    "y": 336.1999969482422,
                    "out_idx": 1,
                    "in_idx": 0,
                    "out": {
                        "1": {
                            "out_id": "6",
                            "name": "写数据库->手写函数"
                        }
                    },
                    "in": {}
                },
                "5": {
                    "temp_name": "发websocket数据",
                    "name": "发websocket数据",
                    "x": 41.399993896484375,
                    "y": 491.1999969482422,
                    "out_idx": 0,
                    "in_idx": 0,
                    "out": {},
                    "in": {}
                },
                "6": {
                    "temp_name": "手写函数",
                    "name": "手写函数",
                    "x": 69.39999389648438,
                    "y": 422.1999969482422,
                    "out_idx": 1,
                    "in_idx": 0,
                    "out": {
                        "1": {
                            "out_id": "5",
                            "name": "手写函数->发websocket数据"
                        }
                    },
                    "in": {}
                }
            }
        }
    }
}   
{
    "now_server":"当前服务器AAA",
    "now_process":"当前进程AAA",
    "next_node":"下一级流程",
    "x":1,
    "y":2,
    "name":"ss",
    "temp_name":"模板名称",
    "in":{},
    "out":{},
    "out_idx":0,
    "in_idx":0,
}